﻿//
// WebTools Library by S. Ali Tokmen
// http://code.google.com/p/web-tools/
// http://ali.tokmen.com/
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// 1. The above copyright notice and this permission notice shall be
//    included in all copies or substantial portions of the Software.
// 2. Namespaces or Class names of the Software components shall not
//    be modified.
// 3. Neither the name of the copyright holders nor the names of its
//    contributors may be used to endorse or promote products derived from
//    this Software without specific prior written permission.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

using System;
using System.IO;
using System.Text;

namespace GoogleCode.WebTools
{
    /// <summary>
    /// Object that represents the payload for uploading POST data.
    /// </summary>
    class MIMEPayload
    {
        private const String boundary = "------------328523758298hjcwuie";
        private byte[] data = new byte[0];

        /// <summary>
        /// Adds a value to the MIME payload.
        /// </summary>
        /// <param name="name">Name of the value to add.</param>
        /// <param name="value">Value to add.</param>
        public void AddValue(String name, String value)
        {
            String text;
            text = "--" + boundary + "\r\n";
            text += "Content-Disposition: form-data; name=\"" + name + "\"\r\n\r\n";
            text += (value == null ? "" : value) + "\r\n";

            byte[] bytes = Encoding.ASCII.GetBytes(text);

            byte[] final = new byte[data.Length + bytes.Length];
            Buffer.BlockCopy(data, 0, final, 0, data.Length);
            Buffer.BlockCopy(bytes, 0, final, data.Length, bytes.Length);
            data = final;
        }

        /// <summary>
        /// Adds a file to the MIME payload.
        /// </summary>
        /// <param name="name">Name of the file to add.</param>
        /// <param name="filePath">Path of the file to add.</param>
        public void AddFile(String name, String filePath)
        {
            String fileName;

            int lastSlash = filePath.LastIndexOf('/');
            int lastBackSlash = filePath.LastIndexOf('\\');

            if (lastSlash == -1)
            {
                // The file path doesn't contain any slash.
                // Check for backslash (Windows).

                if (lastBackSlash == -1)
                {
                    // No slash or backslash, this is a relative path
                    fileName = filePath;
                }
                else
                {
                    // The path only contains a backslash
                    fileName = filePath.Substring(lastBackSlash + 1);
                }
            }
            else
            {
                // The file path contains a slash
                // Therefore, the current platform is probably UNIX.

                if (lastBackSlash == -1)
                {
                    // The path only contains a slash
                    fileName = filePath.Substring(lastSlash + 1);
                }
                else
                {
                    // The path has a slash and a backslash.
                    // That's weird, but non-blocking.
                    fileName = filePath.Substring(Math.Max(lastSlash, lastBackSlash) + 1);
                }
            }

            // MIME header
            String header;
            header = "--" + boundary + "\r\n";
            header += "Content-Disposition: form-data; name=\"" + name + "\"; filename=\"" + fileName + "\"\r\n";
            header += "Content-Type: application/octet-stream\r\n\r\n";
            byte[] headerBytes = Encoding.ASCII.GetBytes(header);

            // MIME content
            byte[] fileBytes;
            using (FileStream fs = File.OpenRead(filePath))
            {
                fileBytes = new byte[fs.Length];
                fs.Read(fileBytes, 0, fileBytes.Length);
            }

            // MIME block
            byte[] final = new byte[data.Length + headerBytes.Length + fileBytes.Length + 2];
            Buffer.BlockCopy(data, 0, final, 0, data.Length);
            Buffer.BlockCopy(headerBytes, 0, final, data.Length, headerBytes.Length);
            Buffer.BlockCopy(fileBytes, 0, final, data.Length + headerBytes.Length, fileBytes.Length);
            final[final.Length - 2] = 13;
            final[final.Length - 1] = 10;
            data = final;
        }

        /// <summary>
        /// Add the end of the MIME payload.
        /// </summary>
        public void Finish()
        {
            byte[] bytes = Encoding.ASCII.GetBytes("--" + boundary + "--");

            byte[] final = new byte[data.Length + bytes.Length];
            Buffer.BlockCopy(data, 0, final, 0, data.Length);
            Buffer.BlockCopy(bytes, 0, final, data.Length, bytes.Length);
            data = final;
        }

        /// <summary>
        /// Get the MIME boundary.
        /// </summary>
        public String Boundary
        {
            get
            {
                return boundary;
            }
        }

        /// <summary>
        /// Get the full MIME data.
        /// </summary>
        public byte[] Data
        {
            get
            {
                return data;
            }
        }
    }
}
